﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.IO;
using System.Drawing;

using SpotItComponents;

using Vitruvian.Distribution;
using Vitruvian.Distribution.SyncPatterns;
using Vitruvian.Serialization;
using Vitruvian.Services;

using Vitruvian.Logging;
using Vitruvian.Testing;

namespace SpotItServerAPI
{
    [ContainsTests("API.DeckManager")]
    [DistributionInfo]
    [OptimisticSerialization]
    public class DeckManager : DistributedManager
    {
        #region Private Data Members
        protected CategoryManager categoryManager = null;
        private string decksDirectory = "";
        private List<Deck> decks = new List<Deck>();
        #endregion
        
        #region Constructors
        public DeckManager() : base("Deck Manager")
        {
            logger = Logger.GetLogger(typeof(DeckManager));
        }
        #endregion

        #region Public Properties and Methods -- Clients can use these methods

        /// <summary>
        /// Available Decks
        /// 
        /// This method will return a list of playing decks (in the Data field of the result) that contains playing deck versions
        /// of all non-private decks or decks own by the current user.
        /// </summary>
        /// <param name="currentSession">current user</param>
        /// <returns></returns>
        [SyncPattern("RPC")]
        public virtual OperationResult AvailablePlayingDecks(Session currentSession)
        {
            OperationMethod mth = new OperationMethod(InternalAvailablePlayingDecks);
            return DoOperation(currentSession, mth, SecurityLevel.Player);
        }

        /// <summary>
        /// Get a Specific Playing Deck
        /// 
        /// This method will return a list of playing decks (in the Data field of the result) that contains playing deck versions
        /// of all non-private decks or decks own by the current user.
        /// </summary>
        /// <param name="currentSession">current user</param>
        /// <param name="deckId">Guid for the deck to retrieve a playing deck for</param>
        /// <returns></returns>
        [SyncPattern("RPC")]
        public virtual OperationResult GetPlayingDeck(Session currentSession, Guid deckId)
        {
            OperationMethod mth = new OperationMethod(InternalGetPlayingDeck);
            return DoOperation(currentSession, mth, SecurityLevel.Player, deckId);
        }


        /// <summary>
        /// Deck Add Method
        /// </summary>
        /// <param name="currentSession">Current user's session, which must be at least for a designer</param>
        /// <param name="newDeck">The deck to add</param>
        /// <returns>A result object, where result.Success = true if the operation was success.  If the operation was not successful,
        /// then result.Success = false and result.ErrorMessage contains the reason why it failed.</returns>
        [SyncPattern("RPC")]
        public virtual OperationResult Add(Session currentSession, Deck newDeck)
        {
            OperationMethod mth = new OperationMethod(InternalAdd);
            return DoOperation(currentSession, mth, SecurityLevel.Designer, newDeck);
        }

        /// <summary>
        /// Deck Remove Method
        /// </summary>
        /// <param name="currentSession">Current user's session, which must be at least for a designer</param>
        /// <param name="existingDeck">The deck to remove. The symbol set id must match one already known to the server.</param>
        /// <returns>A result object, where result.Success = true if the operation was success.  If the operation was not successful, then
        /// result.Success = false and result.ErrorMessage contains the reason why it failed.</returns>
        [SyncPattern("RPC")]
        public virtual OperationResult Remove(Session currentSession, Deck existingDeck)
        {
            OperationMethod mth = new OperationMethod(InternalRemove);
            return DoOperation(currentSession, mth, SecurityLevel.Designer, existingDeck);
        }

        /// <summary>
        /// SymbolSet Update Method
        /// 
        /// Use this method to update the content of a deck, including its cards and categories.  Remember that a deck that you get from the server
        /// is just a local copy.  Any changes that you make to it will not be saved to the server unless you update it.
        /// </summary>
        /// <param name="currentSession">Current user's session, which must be at least for a designer</param>
        /// <param name="existingDeck">The deck to update.  The deck id must match one already known to the server.</param>
        /// <returns>A result object, where result.Success = true if the operation was success.  If the operation was not successful, then
        /// result.Success = false and result.ErrorMessage contains the reason why it failed.</returns>
        [SyncPattern("RPC")]
        public virtual OperationResult Update(Session currentSession, Deck existingDeck)
        {
            OperationMethod mth = new OperationMethod(InternalUpdate);
            return DoOperation(currentSession, mth, SecurityLevel.Designer, existingDeck);
        }

        /// <summary>
        /// Lookup Method
        /// </summary>
        /// <param name="currentSession">Current user's session, which must be at least for a designer</param>
        /// <param name="labelFilter">A string that will act as a filter on the selected deck.  If you pass in a null or empty string, then no
        /// filtering will take place based on the label.  If you pass in a non-empty string, then only filters whose label brings with that non-empty
        /// string will be included in the result set.</param>
        /// <param name="categoryFilter">A category filter. If not null, then only deck in those categories will be returned.
        /// If null, then no filtering take place based on the category</param>
        /// <param name="ownerFilter">A owner filter.  If not null, then only deck belong to that owner will be returned; otherwise no filtering
        /// will be take place based on the owner.</param>
        /// <returns>A result object. If the operation was success, the result.Success = true and result.Data will contain a List<Deck>.
        /// If the operation was not successful, then result.Success = false and result.ErrorMessage contains the reason why it failed.</returns>
        [SyncPattern("RPC")]
        public virtual OperationResult Lookup(Session currentSession, string labelFilter, Category categoryFilter, Guid? ownerFilter)
        {
            OperationMethod mth = new OperationMethod(InternalLookup);
            return DoOperation(currentSession, mth, SecurityLevel.Designer, labelFilter, categoryFilter, ownerFilter);
        }

        /// <summary>
        /// Lookup by Id method
        /// </summary>
        /// <param name="currentSession">Current user's session, which may be at least for a designer</param>
        /// <param name="deckId">The Id of a deck to find.</param>
        /// <returns>A result object. If the operation was success, the result.Success = true and result.Data will contain a Deck.
        /// If the operation was not successful, then result.Success = false and result.ErrorMessage contains the reason why it failed.</returns>
        [SyncPattern("RPC")]
        public virtual OperationResult Lookup(Session currentSession, Guid deckId)
        {
            OperationMethod mth = new OperationMethod(InternalLookupById);
            return DoOperation(currentSession, mth, SecurityLevel.Designer, deckId);
        }

        /// <summary>
        /// ChangeOwnership Method
        /// 
        /// An administrator can use this method to change the owner of all decks that used to be own by one user to another
        /// </summary>
        /// <param name="currentSession">Current user's session, which must by an administrator</param>
        /// <param name="previousOwner">Id of Previous Owner</param>
        /// <param name="newOwner">Id of the New Owner</param>
        /// <returns>A result object, where result.Success = true if the operation was success.  If the operation was not successful, then
        /// result.Success = false and result.ErrorMessage contains the reason why it failed.</returns>
        [SyncPattern("RPC")]
        public virtual OperationResult ChangeOwnership(Session currentSession, Guid previousOwner, Guid newOwner)
        {
            OperationMethod mth = new OperationMethod(InternalChangeOwnerShip);
            return DoOperation(currentSession, mth, SecurityLevel.Admin, previousOwner, newOwner);
        }

        /// <summary>
        /// RemoveAllDecks methods
        /// 
        /// An administrator can use this method to clear out all existing symbol sets.
        /// </summary>
        /// <param name="currentSession">Current user's session, which must by an administrator</param>
        /// <returns>A result object, where result.Success = true if the operation was success.  If the operation was not successful, then
        /// result.Success = false and result.ErrorMessage contains the reason why it failed.</returns>
        [SyncPattern("RPC")]
        public virtual OperationResult RemoveAllDecks(Session currentSession)
        {
            logger.Debug("In RemoveAllDecks");
            OperationMethod mth = new OperationMethod(InternalRemoveAllDecks);
            return DoOperation(currentSession, mth, SecurityLevel.Admin);
        }

        #endregion

        #region Internal Methods for DoOperation
        protected override OperationResult PreCondition()
        {
            OperationResult result = new OperationResult();
            categoryManager = ServiceRegistry.GetPreferredService<CategoryManager>();
            if (categoryManager == null)
                result = new OperationResult("Cannot location a Category Manager -- please restart server process");
            return result;
        }

        private OperationResult InternalAvailablePlayingDecks(object[] opParams)
        {
            OperationResult result = new OperationResult();
            Session currentSession = opParams[0] as Session;

            List<PlayingDeck> playingDecks = new List<PlayingDeck>();
            foreach (Deck deck in decks)
                if (deck.IsPrivate == false || deck.Owner == currentSession.UserInfo.Id)
                    playingDecks.Add(new PlayingDeck(deck));
            result.Data = playingDecks;

            return result;
        }

        private OperationResult InternalGetPlayingDeck(object[] opParams)
        {
            OperationResult result = new OperationResult();
            Session currentSession = opParams[0] as Session;
            Guid deckId = (Guid) opParams[1];

            PlayingDeck playingDeck = null;
            foreach (Deck deck in decks)
                if (deck.IsPrivate == false || deck.Owner == currentSession.UserInfo.Id && deck.Id == deckId)
                {
                    playingDeck = new PlayingDeck(deck);
                    break;
                }
            result.Data = playingDeck;

            return result;
        }

        private OperationResult InternalAdd(object[] opParams)
        {
            OperationResult result;
            Session currentSession = opParams[0] as Session;
            Deck newDeck = opParams[1] as Deck;
            if (newDeck == null)
                result = new OperationResult("No Deck was specified");
            else if (decks.Contains(newDeck))
                result = new OperationResult("The specified Deck already exists, use the update method to change an existing Deck");
            else
            {
                logger.Debug("The symbol set is not already in known, so add it");

                // Make sure all the categories exist
                foreach (Category c in newDeck.Categories)
                    categoryManager.Add(currentSession, c);

                // Add the new symbol set to the list of known sets
                newDeck.Owner = currentSession.UserInfo.Id;
                decks.Add(newDeck);

                // Save the data to a persistent place
                SaveDeck(newDeck);

                result = new OperationResult();
            }
            return result;
        }

        private OperationResult InternalRemove(object[] opParams)
        {
            OperationResult result;
            Deck existingDeck = opParams[1] as Deck;
            if (existingDeck == null)
                result = new OperationResult("No Deck was specified");
            else if (!decks.Contains(existingDeck))
                result = new OperationResult("The specified Deck does not exist");
            else
            {
                decks.Remove(existingDeck);
                SaveDeck(existingDeck);
                result = new OperationResult();
            }

            return result;
        }

        private OperationResult InternalUpdate(object[] opParams)
        {
            OperationResult result = InternalRemove(opParams);
            if (result.Success)
                result = InternalAdd(opParams);
            return result;
        }

        private OperationResult InternalLookup(object[] opParams)
        {
            OperationResult result = new OperationResult();
            List<Deck> foundList = new List<Deck>();

            Session currentSession = opParams[0] as Session;
            string labelFilter = (string) opParams[1];
            Category categoryFilter = opParams[2] as Category;
            Guid? ownerFilter = (Guid?) opParams[3];

            foreach (Deck d in decks)
            {
                logger.DebugFormat("Consider symbol: {0}, {1}, {2}", d.Label, d.IsPrivate, d.Owner);
                if ((string.IsNullOrEmpty(labelFilter) ||
                            (d.Label.Length >= labelFilter.Length && labelFilter.ToLower() == d.Label.Substring(0, labelFilter.Length).ToLower())) &&
                    (categoryFilter == null || d.Categories.Contains(categoryFilter)) &&
                    (ownerFilter == null || ownerFilter == d.Owner) &&
                    (d.IsPrivate == false || d.Owner == currentSession.UserInfo.Id))
                {
                    logger.Debug("Add to result");
                    foundList.Add(d);
                }
            }

            result.Data = foundList;
            return result;
        }

        private OperationResult InternalLookupById(object[] opParams)
        {
            OperationResult result = new OperationResult();

            Session currentSession = opParams[0] as Session;
            Guid symbolSetId = (Guid) opParams[1];
            foreach (Deck d in decks)
            {
                if (d.Id == symbolSetId)
                {
                    if (d.IsPrivate == false || d.Owner == currentSession.UserInfo.Id)
                        result.Data = d;
                    break;
                }
            }

            if (result.Data == null)
                result.ErrorMessage = "Cannot find Deck with the specified id";

            return result;
        }

        private OperationResult InternalChangeOwnerShip(object[] opParams)
        {
            OperationResult result = new OperationResult();

            Guid previousOwner = (Guid)opParams[1];
            Guid newOwner = (Guid)opParams[2];

            foreach (Deck d in decks)
            {
                if (d.Owner.Equals(previousOwner))
                    d.Owner = newOwner;
            }

            return result;
        }

        private OperationResult InternalRemoveAllDecks(object[] opParams)
        {
            decks.Clear();
            return new OperationResult();
        }

        #endregion

        #region Server-only public methods (not used by client)
        public string DecksDirectory
        {
            get { return decksDirectory; }
            set
            {
                decksDirectory = value;
                if (!string.IsNullOrEmpty(decksDirectory))
                    if (!Directory.Exists(decksDirectory))
                        Directory.CreateDirectory(decksDirectory);
            }
        }

        public bool RemoveCategoryFromAllDecks(Session currentSession, Category category)
        {
            bool result = false;

            sessionManager = ServiceRegistry.GetPreferredService<SessionManager>();
            if (sessionManager != null && category!=null)
            {
                Session validatedSession = sessionManager.Validate(currentSession);

                if (validatedSession != null && (validatedSession.UserInfo.IsAdmin || validatedSession.UserInfo.IsDesigner))
                {
                    logger.DebugFormat("Remove category {0} from all symbol sets", category.Label);
                    lock (myLock)
                    {
                        foreach (Deck d in decks)
                            d.Categories.Remove(category);
                    }
                }
            }
            return result;
        }

        #endregion

        #region Save and Load Methods

        protected override void Load()
        {
            lock (myLock)
            {
                // LINQ query for all files containing the word 'Europe'.
                var fileNames = from file in
                                Directory.EnumerateFiles(decksDirectory)
                            where file.ToLower().Contains("Deck - ") && file.ToLower().Contains(".xml")
                            select file;

                // Show results.
                foreach (var fileName in fileNames)
                {
                    Deck d = new Deck();
                    d.Load(fileName);
                    decks.Add(d);
                }
            }
        }

        protected override void Save()
        {
            lock (myLock)
            {
                foreach (Deck d in decks)
                    SaveDeck(d);
            }
        }

        private void SaveDeck(Deck deck)
        {
            string fileName = "";
            string tmpLabel = "";
            if (!string.IsNullOrEmpty(deck.Label))
            {
                tmpLabel = deck.Label.Replace('/', '-');
                tmpLabel = tmpLabel.Replace('\\', '-');
                tmpLabel = tmpLabel.Replace('.', ' ');
                tmpLabel = tmpLabel.Replace(':', '-');
                tmpLabel += " ";
            }

            fileName = "Deck - " + tmpLabel + "(" + Id.ToString() + ").xml";

            if (!string.IsNullOrEmpty(DecksDirectory))
                fileName = DecksDirectory + "/" + fileName;

            deck.Save(fileName);
        }

        #endregion

        #region Reusable Test Setup Methods
        public void Test_SetupSampleDecks(Session testSession)
        {
            OperationResult result;

            CategoryManager categoryManager = ServiceRegistry.GetPreferredService<CategoryManager>();
            categoryManager.Test_SetupTestCategories(testSession);
            List<Category> clist = (categoryManager.Lookup(testSession, "Animals", null)).Data as List<Category>;
            Category animals = clist[0];

            SymbolSet ss1 = new SymbolSet("My Favorite Symbols", true);
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Alligator", new Bitmap("../../../Symbols/Alligator.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Baby Penguin", new Bitmap("../../../Symbols/BabyPenguin.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Bat", new Bitmap("../../../Symbols/Bat.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Bear", new Bitmap("../../../Symbols/Bear.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Beaver", new Bitmap("../../../Symbols/Beaver.jpg")));

            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Bison", new Bitmap("../../../Symbols/Bison.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Bow", new Bitmap("../../../Symbols/Cow.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Crab", new Bitmap("../../../Symbols/Crab.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Dear", new Bitmap("../../../Symbols/Dear.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Dog", new Bitmap("../../../Symbols/Dog.jpg")));

            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Dolphin", new Bitmap("../../../Symbols/Dolphin.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Elephant", new Bitmap("../../../Symbols/Elephant.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Green Fish", new Bitmap("../../../Symbols/Fish-1.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Orange Fishes", new Bitmap("../../../Symbols/Fish-2.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Alligator", new Bitmap("../../../Symbols/Horse.jpg")));

            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Kangaroo", new Bitmap("../../../Symbols/Kangaroo.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Koala", new Bitmap("../../../Symbols/Koala.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Lion", new Bitmap("../../../Symbols/Lion.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Tiger", new Bitmap("../../../Symbols/Tiger.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Lizzard", new Bitmap("../../../Symbols/Lizzard.jpg")));

            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Monkey", new Bitmap("../../../Symbols/Monkey.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Octopus", new Bitmap("../../../Symbols/Octopus.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Owl", new Bitmap("../../../Symbols/Owl.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Penguin", new Bitmap("../../../Symbols/Penguin.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Shark", new Bitmap("../../../Symbols/Shark.jpg")));

            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Snake", new Bitmap("../../../Symbols/Snake.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Squirrel", new Bitmap("../../../Symbols/Squirrel.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Tucan", new Bitmap("../../../Symbols/Tucan.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Whale", new Bitmap("../../../Symbols/Whale.jpg")));
            ss1.AddSymbol(Symbol.CreateSymbolWithLabelImage("Zebra", new Bitmap("../../../Symbols/Zebra.jpg")));

            Assert.IsEqual(30, ss1.Symbols.Count);

            ss1.AddCategory(animals);
            Assert.IsEqual(1, ss1.Categories.Count);

            // CASE 1 - Create a simple deck as many cards as possible using a symbol set
            Image backImage = new Bitmap("../../../Symbols/Background-1.jpg");
            Deck deck1 = new Deck("Test Deck 1", false, backImage);
            DeckSetupDirector director = new DeckSetupDirectorUsingRandomSymbols();
            director.FromSymbolSet = ss1;
            director.TargetDeck = deck1;
            director.Setup();                           // Set up the cards
            Assert.Equals(31, deck1.Cards.Count);

            deck1.Categories.Add(animals);

            result = Add(testSession, deck1);           // Add the deck to the server via the symbol manager,
            Assert.IsTrue(result.Success);              // then make sure it is there by getting the new full
                                                        // list of system sets and seeing if the new set is in
                                                        // that list

            // CASE 2 - Create another deck with a fixed number of cards.
            Deck deck2 = new Deck("Test Deck 2", true, backImage);
            director.NumberOfCards = 16;
            director.TargetDeck = deck2;
            director.Setup();                           // Setup the cards
            Assert.Equals(16, deck2.Cards.Count);

            deck2.Categories.Add(animals);              // Add a category

            result = Add(testSession, deck2);
            Assert.IsTrue(result.Success);

            // CASE 3 - Create another deck with the selected card set
            Deck deck3 = new Deck("Test Deck 3", true, backImage);
            director = new DeckSetupDirectorUsingSelectedSymbols();
            ss1.ClearSelectedSymbols();                 // Clear the selected symbols and then select every other one
            for (int i = 1; i < ss1.Symbols.Count; i = i + 2)
                ss1.Symbols[i].Selected = true;
            director.TargetDeck = deck2;
            director.Setup();                           // Setup the cards
            Assert.Equals(15, deck3.Cards.Count);

            deck3.Categories.Add(animals);              // Add a category

            result = Add(testSession, deck3);
            Assert.IsTrue(result.Success);

        }
        #endregion

        #region Unit Test Cases

#if (DEBUG)
        private Session testSession = null;

        [OneTimeSetup]
        private void Test_DeckManager_Setup()
        {
            sessionManager = ServiceRegistry.GetPreferredService<SessionManager>();
            if (sessionManager == null)
            {
                sessionManager = new SessionManager();
                sessionManager.Init();
                ServiceRegistry.Add(sessionManager);
            }

            categoryManager = ServiceRegistry.GetPreferredService<CategoryManager>();
            if (categoryManager == null)
            {
                categoryManager = new CategoryManager();
                categoryManager.Init();
                ServiceRegistry.Add(categoryManager);
            }

            UserAccount tmpAccount = new UserAccount("tmp", "tmp", "Temporary", "");
            tmpAccount.IsAdmin = true;
            tmpAccount.IsDesigner = true;
            testSession = sessionManager.CreateSession(tmpAccount);
        }


        [Test(1)]
        private void Test_DeckManager_Constructor_and_RemoveAllDecks()
        {
            DeckManager deckManager = new DeckManager();
            deckManager.DecksDirectory = "Decks";
            deckManager.Init();
            Assert.IsNotNull(deckManager.decks);

            OperationResult result = deckManager.RemoveAllDecks(testSession);
            Assert.IsTrue(result.Success);
            Assert.IsNotNull(deckManager.decks);
            Assert.IsEqual(0, deckManager.decks.Count);
        }

        [Test(2)]
        private void Test_DeckManager_Common_Operations()
        {
            DeckManager deckManager = new DeckManager();
            deckManager.DecksDirectory = "Decks";
            deckManager.Init();
            deckManager.RemoveAllDecks(testSession);

            // Get the current full list of system sets
            OperationResult result = deckManager.Lookup(testSession, null, null, null);
            Assert.IsTrue(result.Success);
            List<Deck> currentDecks = result.Data as List<Deck>;
            Assert.IsNotNull(currentDecks);
            Assert.Equals(0, currentDecks.Count);

            // Create a symbol set locally, and then add it to the server via the symbol manager
            // This will test the add method
            deckManager.Test_SetupSampleDecks(testSession);

            // Test Lookup
            result = deckManager.Lookup(testSession, null, null, null);
            Assert.IsTrue(result.Success);
            List<Deck> newDecks = result.Data as List<Deck>;
            Assert.IsNotNull(newDecks);
            Assert.Equals(currentDecks.Count + 3, newDecks.Count);

            // Test AvailablePlayingDecks
            result = deckManager.AvailablePlayingDecks(testSession);
            Assert.IsTrue(result.Success);
            List<PlayingDeck> playDecks = result.Data as List<PlayingDeck>;
            Assert.IsTrue(1 <= playDecks.Count);

            // Test GetPlayingDeck
            Guid deckId = playDecks[0].DeckId;          // Id of Deck to look up directly
            result = deckManager.GetPlayingDeck(testSession, deckId);
            Assert.IsTrue(result.Success);
            PlayingDeck playDeck = result.Data as PlayingDeck;
            Assert.Equals(deckId, playDeck.DeckId);


            // Test Remove
            result = deckManager.Remove(testSession, newDecks[1]);
            Assert.IsTrue(result.Success);

        }

        [Test(3)]
        private void Test_DeckManager_Load_And_Save()
        {
            // TODO
        }

#endif
        #endregion

    }
}
